package leetcode;
/**
 * 139.单词拆分
 * 给定⼀个⾮空字符串 s 和⼀个包含⾮空单词的列表 wordDict，判定 s 是否可以被空格拆分为⼀个或多个在字典中出现的单词。
 * 说明：
 * 拆分时可以重复使⽤字典中的单词。
 * 你可以假设字典中没有重复的单词。
 * 示例 1：
 * 输⼊: s = "leetcode", wordDict = ["leet", "code"]
 * 输出: true
 * 解释: 返回 true 因为 "leetcode" 可以被拆分成 "leet code"。
 * 示例 2：
 * 输⼊: s = "applepenapple", wordDict = ["apple", "pen"]
 * 输出: true
 * 解释: 返回 true 因为 "applepenapple" 可以被拆分成 "apple pen apple"。注意你可以重复使⽤字典中的单词。
 * 示例 3：
 * 输⼊: s = "catsandog", wordDict = ["cats", "dog", "sand", "and", "cat"]
 * 输出: false
 */
import java.util.*;
public class Num_139 {
    //如何转换为背包问题呢？
    public boolean wordBreak(String s, List<String> wordDict) {
        //dp[i]表示前i个字符组成的子串能否被完整拆分成字典中的单词
        boolean[] dp = new boolean[s.length() + 1];
        //假如wordDict=["apple", "pen", "code"],s = "applepencode";
        // dp[8] = dp[5] + check("pen")
        //初始化: null字符串肯定属于字典中
        dp[0] = true;
        //开始遍历子串
        for(int i = 1; i <= s.length(); i++){
            //把字串再次拆分,j表示右半个子串的长度
            for(int j = 1; j <= i; j++){
                if(dp[i - j] && check(s.substring(i - j, i), wordDict)){
                    //左子串是合法字符串，且右子串是合法单词
                    dp[i] = true;
                    //当发现该[0, i-j, i)分区下的字符串合法时，直接跳出内层循环
                    break;
                }
            }
        }
        return dp[s.length()];
    }
    //判断该字符串是否在字典中
    private boolean check(String str, List<String> wordDict) {
        for(int i = 0; i < wordDict.size(); i++){
            if(wordDict.get(i).equals(str)){
                return true;
            }
        }
        return false;
    }
}
